﻿namespace mathD
{
    
    //重构原则2，一个函数，一种用法，不给默认值
    //重构原则3，内部不new，所有计算函数需要外部提供out 参数，最后一个参数为out 参数
    // static vec2Subtract(a: vector2, b: vector2, out: vector2)
    // {
    //     out.x = a.x - b.x;
    //     out.y = a.y - b.y;
    // }
    // static vec2Add(a: vector2, b: vector2, out: vector2) {
    //     out.x = a.x + b.x;
    //     out.y = a.y + b.y;
    // }
    
    export class Vector3
    {
        constructor(x: number = 0, y: number = 0, z: number = 0)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        x: number;
        y: number;
        z: number;
        toString(): string
        {
            return this.x + "," + this.y + "," + this.z;
        }
        private static _up=new Vector3(0,1,0);
        public static get up():Vector3
        {
            return this._up;
        }
        private static _forward=new Vector3(0,0,1);
        public static get forward():Vector3
        {
            return this._forward;
        }
        private static _right=new Vector3(1,0,0);
        public static get right():Vector3
        {
            return this._right;
        }


        static clone(from: Vector3, to: Vector3)
        {
            to.x = from.x;
            to.y = from.y;
            to.z = from.z;
        }

        static add(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            out.x = lhs.x + rhs.x;
            out.y = lhs.y + rhs.y;
            out.z = lhs.z + rhs.z;
        }
       static subtract(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            out.x = lhs.x - rhs.x;
            out.y = lhs.y - rhs.y;
            out.z = lhs.z - rhs.z;
        }
        static minus(a: Vector3, out: Vector3)
        {
            out.x = -a.x;
            out.y = -a.y;
            out.z = -a.z;
        }
        static lengthvalue(a: Vector3): number
        {
            return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
        }
        static SqrLength(value: Vector3): number
        {
            return value.x * value.x + value.y * value.y + value.z * value.z;
        }
        static normalize(value: Vector3, out: Vector3)
        {
            var num: number =Vector3.lengthvalue(value);
            if (num > Number.MIN_VALUE)
            {
                out.x = value.x / num;
                out.y = value.y / num;
                out.z = value.z / num;
            } else
            {
                out.x = 0;
                out.y = 0;
                out.z = 0;
            }
        }
        static scaleByNum(from: Vector3, scale: number, out: Vector3)
        {
            out.x = from.x * scale;
            out.y = from.y * scale;
            out.z = from.z * scale;
        }
        static multiply(a: Vector3, b: Vector3, out: Vector3)
        {
            out.x = a.x * b.x;
            out.y = a.y * b.y;
            out.z = a.z * b.z;
        }
        static cross(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            out.x = lhs.y * rhs.z - lhs.z * rhs.y;
            out.y = lhs.z * rhs.x - lhs.x * rhs.z;
            out.z = lhs.x * rhs.y - lhs.y * rhs.x;
        }
        static dot(lhs: Vector3, rhs: Vector3): number
        {
            return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
        }
        static reflect(inDirection: Vector3, inNormal: Vector3, out: Vector3)
        {
            //return -2 * vector3.Dot(inNormal, inDirection) * inNormal + inDirection;
            var v1: number = 0;
            v1 = this.dot(inNormal, inDirection);
            this.scaleByNum(out, v1 * -2, out);
            this.add(out, inDirection, out);
        }
        static project(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            var num: number = 0;
            num = this.dot(rhs, rhs);
            if (num < Number.MIN_VALUE)
            {
                out.x = out.y = out.z = 0;
            } else
            {
                let num2: number = 0;
                num2 = this.dot(lhs, rhs);
                this.scaleByNum(rhs, num2 / num, out);
            }
        }
        static projectOnPlane(vector: Vector3, planeNormal: Vector3, out: Vector3)
        {
            this.project(vector, planeNormal, out);
            this.subtract(vector, out, out);
        }
        static angleBetween(from: Vector3, to: Vector3): number
        {
            let length=Vector3.lengthvalue(from);
            if(length<=0) return 0;

            length*=Vector3.lengthvalue(to);
            if(length<=0) return 0;

            var result = Vector3.dot(from, to);
            result=result/length;
            result = floatClamp(result, -1, 1);
            result = Math.acos(result) *180/Math.PI;
            return result;
        }
        static distance(lhs: Vector3, rhs: Vector3): number
        {
            var out = pool.new_vector3();
            this.subtract(lhs, rhs, out);
            var result = Math.sqrt(out.x * out.x + out.y * out.y + out.z * out.z);
            pool.delete_vector3(out);
            return result;
        }
        static min(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            out.x = Math.min(lhs.x, rhs.x);
            out.y = Math.min(lhs.y, rhs.y);
            out.z = Math.min(lhs.z, rhs.z);
        }
        static max(lhs: Vector3, rhs: Vector3, out: Vector3)
        {
            out.x = Math.max(lhs.x, rhs.x);
            out.y = Math.max(lhs.y, rhs.y);
            out.z = Math.max(lhs.z, rhs.z);
        }
        static reset(val: Vector3)
        {
            val.x = 0;
            val.y = 0;
            val.z = 0;
        }
        static lerp(lhs: Vector3, rhs: Vector3, lerp: number, out: Vector3)
        {
            out.x = lhs.x * (1 - lerp) + rhs.x * lerp;
            out.y = lhs.y * (1 - lerp) + rhs.y * lerp;
            out.z = lhs.z * (1 - lerp) + rhs.z * lerp;
        }
        static setvalue(x: number, y: number, z: number, out: Vector3)
        {
            out.x = x;
            out.y = y;
            out.z = z;
        }
        ////又有参数又有返回值的必须是static
        static equal(lhs: Vector3, rhs: Vector3, threshold = 0.00001): boolean {
        if (Math.abs(lhs.x - rhs.x) > threshold)
            return false;

        if (Math.abs(lhs.y - rhs.y) > threshold)
            return false;

        if (Math.abs(lhs.z - rhs.z) > threshold)
            return false;

        return true;
        }
    }






}